<template>
  <main id="flow-process-only" @click="handleChangeActived(false)">
    <section class="head">
      <page-header
        :title="projectName"
        @changeTitle="hangleChangeTitle"
      ></page-header>
      <menu-bar
        :actived="actived"
        @changeActived="handleChangeActived"
      ></menu-bar>
      <top-toolbar></top-toolbar>
    </section>
    <section class="body">
      <item-panel class="left"></item-panel>
      <div class="right">
        <breadcrumb
          class="breadcrumb-wrapper"
          :breads="computedBreadArr"
          @changeBreadArr="handleBreadArrChange"
        ></breadcrumb>
        <div class="editor-panel-wrapper" ref="editor-panel-wrapper">
          <div id="editor-panel"></div>
        </div>
        <props-panel></props-panel>
      </div>
      <!-- <div class="minimap-wrapper" ref="minimap-wrapper">
        <div id="minimap"></div>
      </div> -->
    </section>
  </main>
</template>

<script>
import PageHeader from "./components/page-header/index.vue";
import MenuBar from "./components/menu-bar/index.vue";
import TopToolbar from "./components/top-toolbar/index.vue";
import ItemPanel from "./components/item-panel/index.vue";
import breadcrumb from "./components/breadcrumb/index.vue";
import PropsPanel from "./components/props-panel/index.vue";

import GraphEditor from "./core/graph";
import generateNode from "./core/graph/nodes/generateNode";
import EventBus from "./event-bus";
import BusEvents from "./event-bus/event-types";

export default {
  name: "flow-process-only",
  components: {
    PageHeader,
    MenuBar,
    TopToolbar,
    ItemPanel,
    breadcrumb,
    PropsPanel,
  },
  props: {
    projectName: {
      type: String,
      default: "proj1",
    },
    initGraphData: {
      type: Object,
    },
  },
  data() {
    return {
      // 获取 ModelEditor 的 graph 和 dnd 对象，用以操作
      graph: null,
      dnd: null,
      // 其他页面的属性
      hoverItem: {},
      doubleClickNode: { data: { inArr: [], outArr: [] } },
      paramPanelVisible: false,
      resultPanelVisible: false,
      mode: "editing", // editing / viewing

      id2nameMap: new Map(),
      idBreadArr: [],
      // breads: "/",
      // projectGraphData: [], // 整个工程项目的 graphData
      projectGraphData: [], // { cells: [] }
      // currentGraphData: [], // 这是当前 breads 对应的 graphData
      actived: false,
    };
  },
  computed: {
    computedBreadArr() {
      if (this.idBreadArr.length === 0) {
        let breadArr = [];
        breadArr.push(this.projectName);
        return breadArr;
      } else {
        let breadArr = this.idBreadArr.map((nodeId) => {
          return this.id2nameMap.get(nodeId);
        });
        breadArr.unshift(this.projectName);
        return breadArr;
      }
    },
  },
  mounted() {
    this.init();
  },
  beforeDestroy() {
    window.removeEventListener("resize", this.handleResize());
  },
  methods: {
    init() {
      const editorPanelWrapper = this.$refs["editor-panel-wrapper"];
      // const minimapWrapper = this.$refs["minimap-wrapper"];
      const minimap = document.getElementById("minimap"); // 不推荐这么使用
      // const editor = new GraphEditor(editorPanelWrapper, minimapWrapper);
      const editor = new GraphEditor(editorPanelWrapper, minimap);
      this.graph = editor.graph;
      this.dnd = editor.dnd;

      if (this.initGraphData) {
        this.graph.fromJSON(this.initGraphData);
      }

      this.bindEvents();
      this.handleBusEvents();
    },

    /**
     * 监听所有的总线事件
     */
    handleBusEvents() {
      this.handleEventsFromItemPanel();
      this.handleEventsFromMenuBar();
      this.handleEventsFromTopToolbar();
      this.handleEventsFromEditorPanel();
    },
    /**
     * 监听从 item-panel 触发的总线事件
     */
    handleEventsFromItemPanel() {
      EventBus.$on(BusEvents.INTERACT_ITEM_DRAG, ({ nodeData, e }) => {
        const { graph } = this;
        const node = generateNode(graph, nodeData);
        this.dnd.start(node, e);
      });
      EventBus.$on(BusEvents.INTERACT_ADD_NODE, ({ id, name }) => {
        this.id2nameMap.set(id, name);
      });
      EventBus.$on(BusEvents.INTERACT_MOUSE_ENTER, ({ item }) => {
        this.hoverItem = item;
      });
      EventBus.$on(BusEvents.INTERACT_MOUSE_LEAVE, () => {
        this.hoverItem = {};
      });
    },
    /**
     * 监听从 menu-bar 触发的总线事件
     */
    handleEventsFromMenuBar() {
      // undo
      EventBus.$on(BusEvents.COMMAND_UNDO, () => {
        const { graph } = this;
        graph.history.undo();
        graph.cleanSelection();
      });
      // redo
      EventBus.$on(BusEvents.COMMAND_REDO, () => {
        const { graph } = this;
        graph.history.redo();
        graph.cleanSelection();
      });
      // copy
      EventBus.$on(BusEvents.COMMAND_COPY, () => {
        const { graph } = this;
        const cells = graph.getSelectedCells();
        if (cells.length) {
          graph.copy(cells);
        }
      });
      // cut
      EventBus.$on(BusEvents.COMMAND_CUT, () => {
        const { graph } = this;
        const cells = graph.getSelectedCells();
        if (cells.length) {
          graph.cut(cells);
        }
      });
      // paste
      EventBus.$on(BusEvents.COMMAND_PASTE, () => {
        const { graph } = this;
        if (!graph.isClipboardEmpty()) {
          const cells = graph.paste({ offset: 32 });
          graph.cleanSelection();
          graph.select(cells);
        }
      });
      // delete
      EventBus.$on(BusEvents.COMMAND_DELETE, () => {
        const { graph } = this;
        const cells = graph.getSelectedCells();
        if (cells.length) {
          graph.removeCells(cells);
        }
      });
      // save
      EventBus.$on(BusEvents.COMMAND_SAVE, () => {
        const { graph } = this;
        console.log(graph.toJSON());
        // todo: 这里需要发送请求，进行数据的保存
        // const graphData = graph.toJSON();
        // axios.post('/api/postGraphData', { graphData: graphData }).then((res) => {
        //   console.log(res.data);
        // }).catch((err) => {
        //   console.log(err);
        // })
      });
    },
    /**
     * 监听从 top-toolbar 触发的总线事件
     */
    handleEventsFromTopToolbar() {
      // * 将 TopToolbar 中的事件都移到了 MenuBar 中进行统一管理
      // * 因为理论上 TopToolbar 中的命令是 MenuBar 的一部分
    },
    /**
     * 监听从 editor-panel 触发的总线事件
     */
    handleEventsFromEditorPanel() {
      EventBus.$on(BusEvents.INTERACT_DOUBLE_CLICK_NODE, ({ node }) => {
        this.doubleClickNode = node;
        const doubleClickNodeData = node.getData();

        if (doubleClickNodeData.isGroup) {
          // * 1. 将当前 breads 对应的图更新到对应的 breads
          let current = this.idBreadArr.reduce((arr, key) => {
            for (let i = 0; i < arr.length; i++) {
              if (arr[i].id === key) {
                return arr[i].data.kids;
              }
            }
          }, this.projectGraphData);
          current.splice(0, current.length);
          const currentGraphDataArr = this.graph.toJSON()["cells"];
          for (let i = 0; i < currentGraphDataArr.length; i++) {
            current.push(currentGraphDataArr[i]);
          }

          // * 2. 更新 breads
          this.idBreadArr.push(node.id);

          // * 3. 获取双击节点对应的 breads 的图并更新到 graph 上
          let currentGraphData = this.idBreadArr.reduce((arr, key) => {
            for (let i = 0; i < arr.length; i++) {
              if (arr[i].id === key) {
                return arr[i].data.kids;
              }
            }
          }, this.projectGraphData);
          this.graph.fromJSON({ cells: currentGraphData });
        }
      });

      EventBus.$on(BusEvents.INTERACT_UPDATE_ID2NAME_MAP, ({ id, name }) => {
        this.id2nameMap.set(id, name);
      });
    },

    /**
     * 监听 window 事件
     */
    bindEvents() {
      window.addEventListener("resize", this.handleResize());
    },
    handleResize() {
      return debounce(() => {
        const { graph } = this;
        const container = graph.container;
        const width = container.clientWidth;
        const height = container.clientHeight;
        graph.resize(width, height);
        graph.centerContent();
      });

      function debounce(func, wait) {
        let timeout = null;
        return function () {
          const context = this;
          const args = arguments;
          clearTimeout(timeout);
          timeout = setTimeout(() => {
            func.apply(context, args);
          }, wait);
        };
      }
    },

    /**
     * breads 改变
     */
    handleBreadArrChange(clickIndex) {
      // this.idBreadArr = this.idBreadArr.slice(0, clickIndex);
      if (this.idBreadArr.length !== clickIndex) {
        // * 在更新 this.breads 之前更新数据，将 oldBreads 对应的数据更新到 projectGraphData 上
        let current = this.idBreadArr.reduce((arr, key) => {
          for (let i = 0; i < arr.length; i++) {
            if (arr[i].id === key) {
              return arr[i].data.kids;
            }
          }
        }, this.projectGraphData);
        current.splice(0, current.length);
        const currentGraphDataArr = this.graph.toJSON()["cells"];
        for (let i = 0; i < currentGraphDataArr.length; i++) {
          current.push(currentGraphDataArr[i]);
        }
        // * 更新 idbreadArr
        this.idBreadArr = this.idBreadArr.slice(0, clickIndex);
        // * 更新 graph
        let currentGraphData = this.idBreadArr.reduce((arr, key) => {
          for (let i = 0; i < arr.length; i++) {
            if (arr[i].id === key) {
              return arr[i].data.kids;
            }
          }
        }, this.projectGraphData);
        this.graph.fromJSON({ cells: currentGraphData });
      }
    },

    handleChangeActived(newVal) {
      if (this.actived !== newVal) {
        this.actived = newVal;
      }
    },
    hangleChangeTitle(newTitle) {
      if (this.projectName !== newTitle) {
        this.$emit("changeProjectName", newTitle);
      }
    },
  },
};
</script>

<style lang="less">
#flow-process-only {
  width: 100%;
  height: 100%;

  display: flex;
  flex-direction: column;

  .body {
    width: 100%;
    flex: 1;
    position: relative;
    overflow: hidden;

    display: flex;

    .right {
      flex: 1;
      position: relative;

      display: flex;
      flex-direction: column;

      .editor-panel-wrapper {
        width: 100%;
        flex: 1;
      }
    }

    .minimap-wrapper {
      width: 240px;
      height: 160px;
      position: absolute;
      right: 10px;
      bottom: 10px;
      box-sizing: border-box;
      border: 1px solid rgba(0, 0, 0, 0.08);
      border-radius: 4px;
      overflow: hidden;

      display: flex;
      flex-direction: column;
      justify-content: center;
      align-items: center;
    }
  }
}

// 处理 滚动条 样式
.x6-graph-scroller {
  &::-webkit-scrollbar {
    width: 6px;
    height: 6px;
  }
  &::-webkit-scrollbar-thumb {
    border-radius: 3px;
    background: rgba(0, 0, 0, 0.2);
  }
  &::-webkit-scrollbar-track {
    background-color: #f1f1f1;
  }
}
</style>
